package com.cuon.ch09.programobject;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.ArrayList;

import android.content.Context;
import android.util.Log;


public class Data3DList {

	private Context context = null;	// コンテキスト

	private String	 file_path 	= "";						// ファイルパス
	private ByteBuffer bf 		= ByteBuffer.allocate(0);	// datファイルの内容操作用
	private int dat_size 		= 0;						// datファイルのサイズ

	/**
	 * 一覧
	 */
	private ArrayList<Data3D> Data3D_list = new ArrayList<Data3DList.Data3D>();

	/**
	 * コンストラクタ
	 * @param file_path
	 */
	public Data3DList(Context context ) {

		this.context = context;
	}

	/**
	 * datファイルの読込
	 * @param file_path
	 */
	public void readData(String file_path){

		this.file_path = file_path;
		this.Data3D_list = new ArrayList<Data3D>();

		if(Util.isAssetsFileExists(context,file_path,"")){
		// ロゴ画像ファイルが存在している場合
			try {
				// 初期宣言
				InputStream is;

				// assetsフォルダ内のパッケージング画像ファイルを読み込む
				is = context.getResources().getAssets().open(file_path);

				// ファイル読込
				byte[] byte_data3d = Util.getByteArrayFromInputStream(is);

				// datファイルのサイズを保持
				this.dat_size = byte_data3d.length;

				int data_idx = 0;	// データ読み込みインデックス

				while(data_idx < this.dat_size){
				// 読込インデックスがデータサイズ内の場合、繰り返す

					Data3D data3D = new Data3D();

					// パッド番号の取得
					setByteBuffer(byte_data3d,data_idx,4,ByteOrder.LITTLE_ENDIAN);
					data3D.pad_num = bf.getInt();
					data_idx+=4;	// 読込位置を進める

					// データサイズの取得
					setByteBuffer(byte_data3d,data_idx,4,ByteOrder.LITTLE_ENDIAN);
					data3D.pad_data_size = bf.getInt();
					data_idx+=4;	// 読込位置を進める

					// ウィンドウ位置（左上X座標）
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.left_top_X = bf.getShort();
					data_idx+=2;

					// ウィンドウ位置（左上Y座標）
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.left_top_Y = bf.getShort();
					data_idx+=2;

					// ウィンドウ位置（右下X座標）
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.right_bottom_X = bf.getShort();
					data_idx+=2;

					// ウィンドウ位置（右下Y座標）
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.right_bottom_Y = bf.getShort();
					data_idx+=2;

					// 機械分解能
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.machine_resolution = bf.getShort();
					data_idx+=2;

					// 拡張サイズ
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.extended_size = bf.getShort();
					data_idx+=2;

					// 追従量X
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.flatteries_x = bf.getShort();
					data_idx+=2;

					// 追従量Y
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.flatteries_y = bf.getShort();
					data_idx+=2;

					// マスク厚
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.mask_thickness = bf.getShort();
					data_idx+=2;

					// 高分解能フラグ
					setByteBuffer(byte_data3d,data_idx,2,ByteOrder.LITTLE_ENDIAN);
					data3D.high_resolution_flg = bf.getShort();
					data_idx+=2;

					// 予約1
					setByteBuffer(byte_data3d,data_idx,4,ByteOrder.LITTLE_ENDIAN);
					data3D.reservation[0] = bf.getInt();
					data_idx+=4;

					// 予約2
					setByteBuffer(byte_data3d,data_idx,4,ByteOrder.LITTLE_ENDIAN);
					data3D.reservation[1] = bf.getInt();
					data_idx+=4;

					// 予約3
					setByteBuffer(byte_data3d,data_idx,4,ByteOrder.LITTLE_ENDIAN);
					data3D.reservation[2] = bf.getInt();
					data_idx+=4;

					// 形状データ
					data3D.form_data = new byte[(data3D.getWidth() * data3D.getHeight())];
					setByteBuffer(byte_data3d,data_idx,data3D.form_data.length,ByteOrder.BIG_ENDIAN);
					data3D.form_data = bf.array();

					data_idx+=data3D.form_data.length;

					this.Data3D_list.add(data3D);

				}


			} catch (IOException e) {
				// 例外エラー
				e.printStackTrace();
			}
		}

	}

	/**
	 *
	 * @param byte_data3d		3Dデータ
	 * @param idx			取得開始位置
	 * @param size			数
	 * @param byte_order	byteソート
	 */
	private void setByteBuffer(byte[] byte_data3d , int idx , int size , ByteOrder byte_order){
		bf.clear();
		bf = ByteBuffer.allocate(size);
		bf.order(byte_order);
		bf.put(byte_data3d,idx,size);
		bf.position(0);

	}

	public class Data3D{

		/**
		 * パッド番号
		 * データタイプ：long
		 */
		int pad_num = 0;

		/**
		 * パッドデータ データサイズ
		 * データタイプ：long
		 */
		int pad_data_size = 0;


		/**
		 * ウィンドウ位置（左上X座標）
		 * データタイプ：WORD
		 */
		int left_top_X = 0;

		/**
		 * ウィンドウ位置（左上Y座標）
		 * データタイプ：WORD
		 */
		int left_top_Y = 0;


		/**
		 * ウィンドウ位置（右下X座標）
		 * データタイプ：WORD
		 */
		int right_bottom_X = 0;

		/**
		 * ウィンドウ位置（右下Y座標）
		 * データタイプ：WORD
		 */
		int right_bottom_Y = 0;

		/**
		 * 機械分解能
		 * データタイプ：WORD
		 */
		int machine_resolution = 0;

		/**
		 * 拡張サイズ
		 * データタイプ：WORD
		 */
		int extended_size = 0;

		/**
		 * 追従量X
		 * データタイプ：WORD
		 */
		int flatteries_x = 0;

		/**
		 * 追従量Y
		 * データタイプ：WORD
		 */
		int flatteries_y = 0;

		/**
		 * マスク厚
		 */
		int mask_thickness = 0;

		/**
		 * 高分解能フラグ
		 */
		int high_resolution_flg = 0;

		/**
		 * 予約
		 */
		long[] reservation = new long[3];

		/**
		 * 形状データ
		 */
		byte[] form_data = new byte[0];


		/**
		 * 検出ウィンドウの横幅を取得する
		 * @return ウィンドウ位置（右下X座標）- ウィンドウ位置（左上X座標）
		 */
		public int getWidth(){
			return right_bottom_X - left_top_X + 1;
		}

		/**
		 * 検出ウィンドウの横幅を取得する
		 * @return ウィンドウ位置（右下Y座標）- ウィンドウ位置（左上Y座標）
		 */
		public int getHeight(){
			return right_bottom_Y - left_top_Y + 1;
		}

		/**
		 * 3D
		 */
		private float[] output_3D_data = null;
		private byte[] output_3D_Bytedata = null;
		public float[] get3DputData() {

			if(this.output_3D_data == null){
				ArrayList<Float> outputList = new ArrayList<Float>();

				if(this.form_data != null){
					byte[] data = this.form_data;		// 形状データ
					for(int i=0;i<data.length;i++){

						int x = (i % this.getWidth());
						int y = (this.getHeight() - 1) - (i / this.getWidth());
						float z = (data[i]& 0xff);

						float output_x = (x);
						float output_y = (z );		// データは1/2の値で来るため
						float output_z = (y * -1);

						outputList.add(output_x);
						outputList.add(output_y);
						outputList.add(output_z);

						Log.d("x:", "x["+i+"]::"+output_x);
						Log.d("y:", "y["+i+"]::"+output_y);
						Log.d("z:", "z["+i+"]::"+output_z);

					}

					this.output_3D_data = new float[outputList.size()];
					for(int i=0;i<output_3D_data.length;i++){

						this.output_3D_data[i] = outputList.get(i);

					}

				}

			}

			return this.output_3D_data;
		}

		public byte[] get3DByteputData() {

			if(this.output_3D_Bytedata == null){
				ArrayList<Byte> outputList = new ArrayList<Byte>();

				if(this.form_data != null){
					byte[] data = this.form_data;		// 形状データ
					for(int i=0;i<data.length;i++){

						int x = (i % this.getWidth());
						int y = (this.getHeight() - 1) - (i / this.getWidth());
						float z = (data[i]& 0xff);

						byte output_x = Byte.parseByte(String.valueOf(x));
						byte output_y = Byte.parseByte(String.valueOf((z * 2)));		// データは1/2の値で来るため
						byte output_z = Byte.parseByte(String.valueOf((y * -1)));

						outputList.add(output_x);
						outputList.add(output_y);
						outputList.add(output_z);

					}

					this.output_3D_Bytedata = new byte[outputList.size()];
					for(int i=0;i<output_3D_Bytedata.length;i++){

						this.output_3D_Bytedata[i] = outputList.get(i);

					}

				}

			}

			return this.output_3D_Bytedata;
		}

	}

	//----------------------------------------------------------------------------------
	// Getter 及び Setter
	//----------------------------------------------------------------------------------

	/**
	 * @return file_path
	 */
	public String getFilePath() {
		return file_path;
	}

	/**
	 * @return dat_size
	 */
	public int getDatSize() {
		return dat_size;
	}

	/**
	 * NGの3Dデータクラスを一覧で取得する
	 * @return data3D_list
	 */
	public ArrayList<Data3D> getData3DList() {
		return Data3D_list;
	}

	/**
	 * NGの3Dデータクラスを位置を指定して取得する
	 * @param idx
	 * @return
	 */
	public Data3D getData3D(int idx){

		if( 0 <= idx && idx < this.Data3D_list.size() ){
			return this.Data3D_list.get(idx);
		}else{
			return null;
		}
	}

	/**
	 * NG画像のリスト数を取得する
	 * @return
	 */
	public int getNGListCount(){
		return Data3D_list.size();
	}



}
